package cn.xinfei.xdecision.engine.runner.executor.strategy.branch;

import cn.xinfei.xdecision.common.model.component.strategyout.StrategyOutput;
import cn.xinfei.xdecision.common.model.enginex.model.GroupField;
import cn.xinfei.xdecision.common.model.enginex.model.NodeScriptConditions;
import cn.xinfei.xdecision.common.model.enginex.model.NodeScriptModel;
import cn.xinfei.xdecision.common.model.enginex.po.EngineNode;
import cn.xinfei.xdecision.common.utils.constant.CommonConst;
import cn.xinfei.xdecision.common.utils.constant.runner.ParamTypeConst;
import cn.xinfei.xdecision.common.utils.enums.enginex.ConditionValueTypeEnum;
import cn.xinfei.xdecision.common.utils.enums.enginex.NodeTypeEnum;
import cn.xinfei.xdecision.common.utils.util.JsonUtils;
import cn.xinfei.xdecision.common.utils.util.runner.JevalUtil;
import cn.xinfei.xdecision.common.utils.util.runner.jeval.EvaluationException;
import cn.xinfei.xdecision.common.vo.FieldInfoVo;
import cn.xinfei.xdecision.constant.EngineResultEnum;
import cn.xinfei.xdecision.engine.runner.context.AmmunitionDepot;
import cn.xinfei.xdecision.engine.runner.context.PipelineContextHolder;
import cn.xinfei.xdecision.engine.runner.context.XDecisionContext;
import cn.xinfei.xdecision.engine.runner.executor.NodeHandler;
import cn.xinfei.xdecision.engine.runner.executor.XRunner;
import cn.xinfei.xdecision.engine.runner.executor.model.StateTransmitModel;
import cn.xinfei.xdecision.engine.runner.executor.strategy.EngineNodeRunner;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static cn.xinfei.xdecision.engine.runner.executor.model.InterVariableConstant.INTER_GROUP_NODE_CODE;


@XRunner
@Slf4j
@Service
public class Group extends EngineNodeRunner {


    @Override
    public String getServiceName() {
        return EngineNodeRunner.PRE + NodeTypeEnum.CLASSIFY.getType();
    }

    @Override
    public Map<String, StrategyOutput> getTerminalOutputFieldInfo(NodeHandler nodeHandler) {

        Map<String, StrategyOutput> fieldVos = new HashMap<>();

        return fieldVos;
    }
    /**
     * 增加一个内置变量
     *
     * @param nodeHandler
     * @return
     */
    @Override
    public Map<String, StrategyOutput> getOutputFieldInfo(NodeHandler nodeHandler) {
        Map<String, StrategyOutput> outputResult = new HashMap<>();
        StrategyOutput output = new StrategyOutput();
        output.setFieldCode(INTER_GROUP_NODE_CODE);
        output.setFieldValue(INTER_GROUP_NODE_CODE);
        output.setVarValueType(2);
        output.setStage(2);//过程
        output.setValueType(ConditionValueTypeEnum.VARIABLE.getCode());
        outputResult.put(INTER_GROUP_NODE_CODE, output);
        return outputResult;
    }

    @Override
    public Map<String, FieldInfoVo> getInputFieldInfo(NodeHandler nodeHandler) {
        EngineNode engineNode = nodeHandler.getEngineNode();
        String engineCode = engineNode.getEngineCode();
        if (engineCode.equalsIgnoreCase("jcl_20230524000001")) {
            System.out.println();
        }
        log.debug("获取分组节点指标 getNodeFieldName engineNode:{}", engineNode.toSimpleString());
        Map<String, FieldInfoVo> fieldVos = new HashMap<>();
        NodeScriptModel nodeScriptModel = JSONObject.parseObject(engineNode.getNodeScript(), NodeScriptModel.class);
        if (null != nodeScriptModel) {
            List<GroupField> fields = nodeScriptModel.getFields();
            Map<String, FieldInfoVo> fieldInfo = metadataProvider.getFieldInfo();
            for (int i = 0; i < fields.size(); i++) {
                GroupField input = fields.get(i);
                String fieldCode = input.getFieldCode();
                FieldInfoVo value = fieldInfo.get(fieldCode);
                if (value != null) {
                    fieldVos.put(fieldCode, value);
                }
            }
        }
        return fieldVos;
    }


    @Override
    public StateTransmitModel runNode(NodeHandler nodeHandler) {
        EngineNode engineNode = nodeHandler.getEngineNode();
        String nodeCode = engineNode.getNodeCode();
        NodeScriptModel nodeScriptModel = JSONObject.parseObject(engineNode.getNodeScript(), NodeScriptModel.class);
        String nextNode = null;
        try {
            nextNode = handleClassify(nodeScriptModel);
        } catch (Exception e) {
            log.error("执行分组节点异常,error={}", e.getMessage(), e);
        }
        if (StringUtils.isNotEmpty(nextNode)) {
            PipelineContextHolder.putInContext(nodeCode, INTER_GROUP_NODE_CODE, nextNode);
        }else{
            log.error("分组节点没有获取到nextNodeCode信息,nodeScriptModel={}", JsonUtils.toJsonString(nodeScriptModel));
            return XDecisionContext.getContext().getStateContext().setEngineResultEnum(EngineResultEnum.EXCEPTION_NO_NEXT_END);
        }
        log.info("执行分组节点 runNode nodeCode:{},nextNode:{}", nodeCode, nextNode);

        return XDecisionContext.getContext().getStateContext().setNextNodeCode(nextNode);

    }

    private static String handleClassify(NodeScriptModel nodeScriptModel) throws EvaluationException {
        List<NodeScriptConditions> conditions = nodeScriptModel.getConditions();
        Map<String, Integer> fieldTypeMap = nodeScriptModel.getFieldTypeMap();

       Map<String, Object> inputParamValues=new HashMap<>();
        fieldTypeMap.entrySet().forEach(e->{
            String fieldCode = e.getKey();
            Object valueByKey = AmmunitionDepot.getValueByKeyFromRemote(ParamTypeConst.VARIABLE, fieldCode, fieldCode);
            if(null!=valueByKey) {
                inputParamValues.put(fieldCode, valueByKey);
            }
        });

        AmmunitionDepot.convertVariables(fieldTypeMap, inputParamValues);

        String nextNode = "";
        if (conditions == null || conditions.isEmpty()) {
            //TODO shiyusen 如果为空，说明是藏数据，理论上不能部署，需要完整性校验
            return nextNode;
        }
        int size = conditions.size();
        boolean flag = false;
        NodeScriptConditions condition = null;
        for (int i = 0; i < size; i++) {
            condition = conditions.get(i);
            //公式为空，则为else条件分支
            String formulaScript = condition.getFormulaScript();
            if (CommonConst.STRING_EMPTY.equals(formulaScript)) {
                //else条件
                if (nextNode.equals(CommonConst.STRING_EMPTY)) {
                    nextNode = condition.getNextNode();
                }
            } else {
                //正常条件分支
                flag = JevalUtil.evaluateBoolean(formulaScript, inputParamValues);
                if (flag) {
                    log.info("命中当前分支，branchName={},nextCode={},formulaScript={}", condition.getGroupName(), condition.getNextNode(), formulaScript);
                    nextNode = condition.getNextNode();
                    break;
                }
            }
        }
        return nextNode;
    }



    @Override
    public boolean terminalCondition(NodeHandler nodeHandler, Map<String, Object> nodeOutput, Map<String, Object> nodeInput) {
        return false;
    }
}
